package wiModel;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import wiBase.WiException;

/**
 * handler for parser.
 */
public class WiModelParser extends DefaultHandler {

    private static final boolean FLAG_DEBUG = true;
    String fileName = "./res/trace/trace.xml";

    public WiModelParser() {
    }

    /**
     * create WiModelParser for parse
     *
     * @param fileName: path of trace file.
     */
    public WiModelParser(String fileName) throws WiException {
	this.fileName = fileName;
    }

    /**
     *	start parse() trace file
     */
    public void parse() throws WiException {
	parse(fileName);
    }
    /**
     *	start parse with path of trace file
     */
    public void parse(String fileName) throws WiException {
	try {
	    parseTraceFile(fileName);
	} catch (ParserConfigurationException | SAXException | IOException e) {
	    throw new WiException(WiException.TYPE_MODEL_EX, e.toString());
	}
    }

    private void parseTraceFile(String fileName)
	    throws ParserConfigurationException, SAXException, IOException {
	// the SAXParserFactory class that creates the parser instance used.
	SAXParserFactory spf = SAXParserFactory.newInstance();
	spf.setNamespaceAware(true);

	/*
	 * Throws a ParserConfigurationException if it cannot produce a parser
	 * that matches the specified configuration of options.
	 */
	SAXParser saxParser = spf.newSAXParser();

	/*
	 * The SAXParser class, which is what the factory returns for parsing.
	 */
	XMLReader xmlReader = saxParser.getXMLReader();

	/* Set listener for parse SAX */
	WiModelParserHandler _handler = new WiModelParserHandler(fileName);
	_handler.setProtocolListener(new WiModelProtocol());	// set callback

	xmlReader.setContentHandler(_handler);

	/* StartParse */
	long start = System.currentTimeMillis();
	if (!FLAG_DEBUG) {
	    File f = new File(fileName);
	    InputStream is = new FileInputStream(f);

	    BufferedReader br = new BufferedReader(new InputStreamReader(is));

	    sb = new StringBuilder();
	    System.gc();
	    String line;
	    while ((line = br.readLine()) != null) {
		sb.append(line);
	    }
	    br.close();
	    long end = System.currentTimeMillis();

	    System.out.println("sum read file: " + (end - start) + "ms"); //207ms

	    InputSource source = new InputSource(new StringReader(sb.toString()));
	    xmlReader.parse(source);
	} else {
	    xmlReader.parse(convertToFileURL(fileName));
	}



	/* It is safer to implement some error handling. */
	xmlReader.setErrorHandler(new WiModelParserException(System.err));

    }
    static StringBuilder sb;

    private static String convertToFileURL(String filename) {
	String path = new File(filename).getAbsolutePath();
	if (File.separatorChar != '/') {
	    path = path.replace(File.separatorChar, '/');
	}

	if (!path.startsWith("/")) {
	    path = "/" + path;
	}
	return "file:" + path;
    }
}
